﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Security;
using System.Transactions;
using TRL.DataAccessLayer;

namespace TRL.TRLAdmin.UserMgmt
{
    public partial class AddEditUser : System.Web.UI.Page
    {
        public enum Mode { AddUser, EditUser };
        public Mode OperationMode { private set; get; }

        private string _userFullName;
        public string UserFullName
        {
            private set
            {
                this._userFullName = value;
                ViewState["UserFullName"] = value;
            }
            get
            {
                if (this._userFullName != null)
                {
                    return this._userFullName;
                }
                else
                {
                    if (Request.QueryString["userFullName"] != null)
                        return Request.QueryString["userFullName"];
                    else if (ViewState["UserFullName"] != null)
                         return ViewState["UserFullName"].ToString();
                    else
                        return "";
                }
            }
        }

        // Maintains the userId the form is operating on.
        // When this page is called by the View Users grid, the userId is passed as a querystring paramter.
        // However, when this page is loaded by an Edit operation, it's called by itself and we
        // use ViewState to maintain the userId. This property maintains the userId in both cases.
        private Guid? _userId;
        public Guid? UserId {
            private set
            {
                this._userId = value;
                ViewState["UserId"] = value;
            }
            get
            {
                if (this._userId != null)
                {
                    return this._userId;
                }
                else
                {
                    if (Request.QueryString["userId"] != null)
                        return new Guid(Request.QueryString["userId"]);
                    else if (ViewState["userId"] != null)
                        return new Guid(ViewState["userId"].ToString());
                    else
                        return null;
                }
            }        
        }

        // Methods of this page
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                // If the page is requested and it's:
                // 1) Not a postback
                // 2) The mode querystring paramater is not specified or it's specified as "insert",
                // display add user form otherwise display edit user form.
                if (String.IsNullOrEmpty(Request.QueryString["mode"]) || Request.QueryString["mode"].ToString() == "insert")
                {
                    OperationMode = Mode.AddUser;
                    AddEditUserFormView.ChangeMode(FormViewMode.Insert);
                }
                else
                {
                    OperationMode = Mode.EditUser;
                    AddEditUserFormView.ChangeMode(FormViewMode.Edit);
                }
            }
            else
            {
                if (AddEditUserFormView.CurrentMode == FormViewMode.Insert)
                    OperationMode = Mode.AddUser;
                else
                    OperationMode = Mode.EditUser;
            }
        }

        /// <summary>
        ///  Displays the approriate insert or edit button based on the mode.
        ///  We put this logic in the PreRender method as the mode may be changed
        ///  by a button OnClick event handler.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_PreRender(object sender, EventArgs e)
        {
            var addButton = AddEditUserFormView.FindControl("AddButton") as Button;
            var updateButton = AddEditUserFormView.FindControl("UpdateButton") as Button;
            var deleteButton = AddEditUserFormView.FindControl("DeleteButton") as Button;

            if (OperationMode == Mode.AddUser)
            {
                addButton.Visible = true;
                updateButton.Visible = false;
                deleteButton.Visible = false;
            }
            else
            {
                addButton.Visible = false;
                updateButton.Visible = true;
                deleteButton.Visible = true;

                // Set the delete button to call the Javascript function that confirms the deletion of the user.
                // We do that here instead of in the aspx page as need to set the paramaters of confirmDeleteUser
                // based on varaibles in this class.
                deleteButton.OnClientClick = String.Format("confirmDeleteUser('{0}', '{1}'); return false;", UserId, UserFullName);

            }
        }


        private enum MessageType { Success, Error }
        /// <summary>
        /// Displays an error message to the user.
        /// </summary>
        /// <param name="msg"></param>
        private void displayMessage(MessageType type, string msg)
        {
            if (type == MessageType.Error)
                message.CssClass = "alert alert-error";
            else
                message.CssClass = "alert alert-success";

            message.Visible = true;
            message.Text = msg;
        }

        /// <summary>
        /// A DTO object that contains the fields the AddUser and EditUser methods need.
        /// Created so we don't repeat this code.
        /// </summary>
        class ControlsForAddEditUser
        {
            public TextBox Username { get; private set; }
            public TextBox FullName { get; private set; }
            public TextBox Email { get; private set; }
            public TextBox Password { get; private set; }
            public TextBox ConfirmPassword { get; private set; }

            public ControlsForAddEditUser(FormView AddEditUserFormView)
            {
                Username = AddEditUserFormView.FindControl("Username") as TextBox;
                FullName = AddEditUserFormView.FindControl("FullName") as TextBox;
                Email = AddEditUserFormView.FindControl("Email") as TextBox;
                Password = AddEditUserFormView.FindControl("Password") as TextBox;
                ConfirmPassword = AddEditUserFormView.FindControl("ConfirmPassword") as TextBox;
            }
        }

        private bool validatePasswordAndConfirmPassword(ControlsForAddEditUser c)
        {
            if (c.Password.Text != c.ConfirmPassword.Text)
            {
                displayMessage(MessageType.Error, "The password and confirm passwod do not match. Please re-enter the passwords.");
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// Adds an Admin User.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void AddButton_Click(object sender, EventArgs e)
        {
            var c = new ControlsForAddEditUser(AddEditUserFormView);

            if (!validatePasswordAndConfirmPassword(c))
                return;
            
            var currernUserId = Membership.GetUser().ProviderUserKey as Guid?; 
            try
            {
                using (var ts = new TransactionScope())
                {
                    var dc = new DataClasses1DataContext();
                    var membership = Membership.CreateUser(c.Username.Text, c.Password.Text, c.Email.Text);
                    
                    var userInfo = new AdminUserInfo
                    {
                        userId = (Guid)membership.ProviderUserKey,
                        fullName = c.FullName.Text,
                        lastModifiedBy = currernUserId,
                        lastModifiedOn = DateTime.Now,
                    };
                    dc.AdminUserInfos.InsertOnSubmit(userInfo);
                    dc.SubmitChanges();
                    ts.Complete();
                }
                displayMessage(MessageType.Success, "User for " + c.FullName.Text + " successfully created.");
            }
            catch (MembershipCreateUserException ex)
            {
                displayMessage(MessageType.Error, GetErrorMessageFromMembershipCreation(ex.StatusCode));
            }
        }

        /// <summary>
        /// Updates an Admin User. 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void UpdateButton_Click(Object sender, EventArgs e)
        {
            var c = new ControlsForAddEditUser(AddEditUserFormView);

            if (!validatePasswordAndConfirmPassword(c))
                return;

            var currernUserId = (Guid)Membership.GetUser().ProviderUserKey;

            try
            {
                using (var ts = new TransactionScope())
                {
                    var membership = Membership.GetUser(UserId);
                    membership.Email = c.Email.Text;
                    Membership.UpdateUser(membership);

                    if (c.Password.Text != "")
                    {
                        try
                        {
                            membership.ChangePassword(membership.ResetPassword(), c.Password.Text);
                        }
                        catch (Exception ex)
                        {
                            displayMessage(MessageType.Error, "Unable to change password. Error: " + ex.Message);
                            return;
                        }
                    }

                    var dc = new DataClasses1DataContext();

                    var userInfo =
                        (from u in dc.AdminUserInfos
                            where u.userId == UserId
                            select u).First();
                    UserFullName = c.FullName.Text;
                    userInfo.fullName = UserFullName;
                    userInfo.lastModifiedOn = DateTime.Now;
                    userInfo.lastModifiedBy = currernUserId;

                    var userRow =
                        (from u in dc.aspnet_Users
                            where u.UserId == UserId
                            select u).First();
                    userRow.UserName = c.Username.Text;
                    userRow.LoweredUserName = c.Username.Text.ToLower();

                    dc.SubmitChanges();
                    ts.Complete();

                    displayMessage(MessageType.Success, "User successfully updated.");
                }
            }
            catch (Exception ex)
            {
                displayMessage(MessageType.Error, "Error updating user. If you changed the username, the new username could be in use. Error: " + ex.Message);
            }

            // Setup the page so that it renders an Edit User form of the current user.
            // Otherwise it returns to an Add User form.
            OperationMode = Mode.EditUser;
            AddEditUserFormView.DefaultMode = FormViewMode.Edit;
        }

        /// <summary>
        /// Called when Cancel Button is clicked. Either clears form if in Add Member mode, or if in Edit Member mode
        /// redirects users to View Members page.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void CancelButton_Click(object sender, EventArgs e)
        {
            if (OperationMode == Mode.AddUser)
            {
                Response.Redirect("AddEditUser.aspx", true);
            }
            else
            {
                Response.Redirect("viewUsers.aspx", true);
            }
        }

        public string GetErrorMessageFromMembershipCreation(MembershipCreateStatus status)
        {
            switch (status)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "Username already exists. Please choose a different username.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "A user for that e-mail address already exists.";

                case MembershipCreateStatus.InvalidPassword:
                    return "The password provided is invalid.";

                case MembershipCreateStatus.InvalidEmail:
                    return "The e-mail address provided is invalid.";

                case MembershipCreateStatus.InvalidUserName:
                    return "The username provided is invalid. Please choose another username.";

                case MembershipCreateStatus.ProviderError:
                    return "The authentication provider returned an error. Please verify your information and try again. If the problem persists, please contact the TRL system administrator.";

                case MembershipCreateStatus.UserRejected:
                    return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact the TRL system administrator.";

                default:
                    return "An unknown error occurred. Please verify your information and try again. If the problem persists, please contact the TRL system administrator.";
            }
        }

            
    }
}